package com.hydra.wiki.lucene.server;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.hydra.wiki.lucene.common.IRResult;
import com.hydra.wiki.lucene.common.IqlAnalyse;
import com.hydra.wiki.lucene.common.IqlAnalyseInter;
import com.hydra.wiki.lucene.constant.IndexConf;
import org.apache.commons.lang.ArrayUtils;
import org.apache.log4j.Logger;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.MultiReader;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.TopFieldDocs;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.SimpleFragmenter;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;

public class DocQueryImpl implements DocQueryInter {
    static boolean IsQueryAble = true;
    private static Logger log = Logger.getLogger(DocQueryImpl.class);
    private File indexFile = null;
    private List<File> indexFiles = null;

    private DocQueryImpl() {
    }

    /**
     * 工厂类
     *
     * @param indexFile
     * @return
     */
    public static DocQueryInter getInstance(File indexFile) {
        DocQueryImpl docQuery = new DocQueryImpl();
        docQuery.indexFile = indexFile;
        return docQuery;
    }

    /**
     * 工厂类
     *
     * @param indexFile
     * @return
     */
    public static DocQueryInter getInstance(List<File> indexFiles) {
        DocQueryImpl docQuery = new DocQueryImpl();
        docQuery.indexFiles = indexFiles;
        return docQuery;
    }

    @Override
    public IRResult query(String Iql, int currentPage, int pagesize)
            throws Exception {
        if (!IsQueryAble) {
            return IRResult.getInstance(1);
        }
        IndexSearcher searcher = null;
        Directory directory = null;
        IRResult Result = null;
        long startTime = new Date().getTime();

        try {
            log.debug("EXCUTE-IQL:" + Iql + " at " + indexFile.getPath());
            IqlAnalyseInter iqlAnalyse = new IqlAnalyse(Iql, currentPage,
                    pagesize);
            directory = FSDirectory.open(indexFile);

            IndexReader reade = IndexReader.open(directory);
            searcher = new IndexSearcher(reade);
            QueryParser mqp = new MultiFieldQueryParser(Version.LUCENE_35,
                    iqlAnalyse.getLimitTitle(), new IKAnalyzer());
            Query qp = mqp.parse(iqlAnalyse.getLimitValue());
            // 在索引器中使用IKSimilarity相似度评估器
            // searcher.setSimilarity( new IKAnalyzer())
            // 使用IKQueryParser查询分析器构造Query对象
            // 开始排序----------------------------------------------------
            Sort sort = iqlAnalyse.getSortTitle();
            TopFieldDocs search = searcher.search(qp, Integer
                    .valueOf(iqlAnalyse.getMaxTopNum()), sort);
            // 开始结束----------------------------------------------------
            // // 搜索相似度最高的5条记录
            // TopDocs topDocs = isearcher.search(query, Integer
            // .valueOf(iqlAnalyse.getMaxTopNum()));
            ScoreDoc[] sco = search.scoreDocs;
            int totleSize = sco.length;
            // 将结果截取用户需要的
            sco = iqlAnalyse.subDoc(sco);
            List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
            for (int i = 0; i < sco.length; i++) {
                Document targetDoc = searcher.doc(sco[i].doc);
                list.add(splitDoc(targetDoc, qp, iqlAnalyse.getLimitTitle()));
            }
            Result = IRResult.getInstance(currentPage);
            Result.setPageSize(pagesize);
            Result.setTotleSize(totleSize);
            Result.setResultList(list);

        } catch (IOException e) {
            log.error("商品索引检索：" + e.getMessage());
            throw new RuntimeException(e.getMessage());
        } finally {
            if (searcher != null) {
                try {
                    searcher.close();
                } catch (IOException e) {
                    log.error(e.getMessage());
                }
            }
            if (directory != null) {
                try {
                    directory.close();
                } catch (IOException e) {
                    log.error(e.getMessage());
                }
            }

        }
        long endTime = new Date().getTime();
        log.debug("共检索到记录" + Result.getTotleSize() + "条，用时"
                + (endTime - startTime) + "毫秒");
        Result.setRuntime(endTime - startTime);
        Result.setTotalPage((Result.getTotleSize() - 1) / Result.getPageSize()
                + 1);
        return Result;
    }

    protected Map<String, Object> splitDoc(Document node, Query query,
                                           String[] fields) throws Exception {
        Map<String, Object> map = new HashMap<String, Object>();
        // 高亮显示{--
        SimpleHTMLFormatter simpleHTMLFormatter = new SimpleHTMLFormatter(
                IndexConf.getString("config.file.lucene_highLight_simple_s"),
                IndexConf.getString("config.file.lucene_highLight_simple_e"));
        Highlighter highlighter = new Highlighter(simpleHTMLFormatter,
                new QueryScorer(query));
        // --}
        for (Fieldable feild : node.getFields()) {
            String title = feild.name().toUpperCase();
            String value = node.get(feild.name());
            // 如果处理字段是ID的话就不加标红处理
            if (title.equals("ID")) {
                map.put(title, value);
                continue;
            }
            if (ArrayUtils.contains(fields, title)) {
                // 标红处理
                // 高亮词{--
                String highLight = null;
                /**
                 * <--------------------
                 * 2013-10-30王东，问题：页面上高亮关键字被截断导致样式扩散，处理：将下面语句从209行移植到该处
                 */
                int textLength = Integer.valueOf(IndexConf
                        .getString("config.file.lucene_highLight_maxnum"));

                if (value.length() > textLength) {
                    value = value.substring(0, textLength);
                }
                /**
                 * ---------------->
                 */
                // 做标题关键字标红
                {
                    highlighter
                            .setTextFragmenter(new SimpleFragmenter(
                                    Integer
                                            .valueOf(IndexConf
                                                    .getString("config.file.lucene_highLight_maxnum"))));
                    String text = node.get(title).replace("\n", "").replace(
                            "\t", "").replace(" ", "");
                    Analyzer analyzer = new IKAnalyzer();
                    TokenStream tokenStream = analyzer.tokenStream(title
                            .toUpperCase(), new StringReader(text));
                    try {
                        highLight = highlighter.getBestFragment(tokenStream,
                                text);
                    } catch (IOException e) {
                        log.error(e.getMessage());
                    }
                }
                if (highLight != null) {
                    value = highLight;
                }
            }
            // --}

            map.put(title, value);
        }
        return map;
    }

    @Override
    public IRResult queryByMultiIndex(String Iql, int currentPage, int pagesize)
            throws Exception {
        if (!IsQueryAble) {
            return IRResult.getInstance(1);
        }
        IndexSearcher searcher = null;
        Directory directory = null;
        IRResult Result = null;
        long startTime = new Date().getTime();

        try {
            log.debug("EXCUTE-IQL:" + Iql + " at " + indexFiles);
            IqlAnalyseInter iqlAnalyse = new IqlAnalyse(Iql, currentPage,
                    pagesize);
            // 查询构造
            QueryParser mqp = new MultiFieldQueryParser(Version.LUCENE_35,
                    iqlAnalyse.getLimitTitle(), new IKAnalyzer());
            Query qp = mqp.parse(iqlAnalyse.getLimitValue());
            // 开始排序----------------------------------------------------
            Sort sort = iqlAnalyse.getSortTitle();
            // 索引文件集合
            IndexReader[] readers = new IndexReader[indexFiles.size()];
            for (int i = 0; i < indexFiles.size(); i++) {
                if (!indexFiles.get(i).isDirectory()) {
                    // 打开后立即关闭相当于初始化索引目录。
                    DocIndexImpl.getInstance(indexFiles.get(i)).close();
                }
                directory = FSDirectory.open(indexFiles.get(i));
                IndexReader reade = IndexReader.open(directory);
                readers[i] = reade;
            }
            MultiReader mr = new MultiReader(readers);
            searcher = new IndexSearcher(mr);
            TopFieldDocs search = searcher.search(qp, Integer
                    .valueOf(iqlAnalyse.getMaxTopNum()), sort);
            // 开始结束----------------------------------------------------
            // // 搜索相似度最高的5条记录
            // TopDocs topDocs = isearcher.search(query, Integer
            // .valueOf(iqlAnalyse.getMaxTopNum()));
            ScoreDoc[] sco = search.scoreDocs;
            int totleSize = sco.length;
            // 将结果截取用户需要的
            sco = iqlAnalyse.subDoc(sco);
            List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
            for (int i = 0; i < sco.length; i++) {
                Document targetDoc = searcher.doc(sco[i].doc);
                list.add(splitDoc(targetDoc, qp, iqlAnalyse.getLimitTitle()));
            }
            Result = IRResult.getInstance(currentPage);
            Result.setPageSize(pagesize);
            Result.setTotleSize(totleSize);
            Result.setResultList(list);

        } catch (IOException e) {
            log.error("商品索引检索：" + e.getMessage());
            throw new RuntimeException(e.getMessage());
        } finally {
            if (searcher != null) {
                try {
                    searcher.close();
                } catch (IOException e) {
                    log.error(e.getMessage());
                }
            }
            if (directory != null) {
                try {
                    directory.close();
                } catch (IOException e) {
                    log.error(e.getMessage());
                }
            }

        }
        long endTime = new Date().getTime();
        log.debug("共检索到记录" + Result.getTotleSize() + "条，用时"
                + (endTime - startTime) + "毫秒");
        Result.setRuntime(endTime - startTime);
        Result.setTotalPage((Result.getTotleSize() - 1) / Result.getPageSize()
                + 1);
        return Result;
    }
}
